/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.hunter.desktop.file.fetch;

import java.io.File;
import java.util.Deque;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.Queue;

import com.hunter.desktop.file.FileData;
import com.hunter.desktop.file.FileDataFactory;
import com.hunter.desktop.file.content.ContentChooser;
import com.hunter.desktop.file.content.NeverContentChooser;

/**
 * 文件抓取，与遍历的类
 * 
 * @author bastengao
 */
public class FileFetcher implements Fecther<FileData> {

	private File[] files;// 被索引的文件
	private Chooser chooser;// 文件选择策略
	@SuppressWarnings("unused")
	private ContentChooser contentChooser;// 内容选择策略
	private FileDataFactory fileDataFactory = new FileDataFactory();// fileData

	/**
	 * 默认 contentChooser 为 NeverContentChooser
	 * 
	 * @param files
	 *            被索引的文件
	 * @param chooser
	 *            文件选择策略
	 */
	public FileFetcher(File[] files, Chooser chooser) {
		this.files = files;
		this.chooser = chooser;
		this.contentChooser = new NeverContentChooser();
	}

	/**
	 * 
	 * @param files
	 *            被索引的文件
	 * @param chooser
	 *            文件选择策略
	 * @param contentChooser
	 *            内容选择策略
	 */
	public FileFetcher(File[] files, Chooser chooser,
			ContentChooser contentChooser) {
		this.files = files;
		this.chooser = chooser;
		this.contentChooser = contentChooser;
	}

	/**
	 * 返回 FileData 的迭代
	 */
	@Override
	public Enumeration<FileData> iterator() {
		return new FileIterator();
	}

	/**
	 * 迭代器的实现 深度遍历 ,此类不是线程安全的
	 * 
	 * @author bastengao
	 * 
	 */
	public class FileIterator implements Enumeration<FileData> {

		// 用的是双端队列，其实是把它当做栈来使用
		Deque<File> fileStack = new LinkedList<File>();// 范围，起始文件
		Queue<File> readyToIndex = new LinkedList<File>();// 已经过滤好的文件，将要索引的文件

		public FileIterator() {
			filter(files);
			ensureHasFileToIndex();
		}

		@Override
		public boolean hasMoreElements() {
			return readyToIndex.size() > 0;
		} 

		@Override
		public FileData nextElement() {
			File indexFile = readyToIndex.poll();
			ensureHasFileToIndex();
			FileData fileData = null; 
			try {
				fileData = fileDataFactory.createFileData(indexFile);
			} catch (IllegalArgumentException ex) {
				// TODO these code has mistakes;
				ex.printStackTrace();
				fileData = nextElement();
			}
			return fileData;
		}

		private void ensureHasFileToIndex() {
			// 一直过滤，直到找到可以索引的文件，除非没有文件可找
			while (readyToIndex.size() == 0 && fileStack.size() != 0) {
				File file = fileStack.removeFirst();
				filter(file);
			}
		}

		/**
		 * 
		 * @param files
		 */
		private void filter(File[] files) {
			for (File file : files) {
				filter(file);
			}
		}

		private void filter(File file) {
			if (file.isDirectory()) {// 如果是文件夹则把他的所有子文件（包括文件夹）添加到栈
				if (file.listFiles() != null) {
					for (File child : file.listFiles()) {
						fileStack.offerFirst(child);
					}
				}
			}
			if (chooser.accept(file)) {// 如果这个文件是应该被接受索引的，则添加到了索引队列
				readyToIndex.offer(file);
			}

		}
	}
}
